/*
 * Copyright (c) United Binary LLC.  All rights reserved.
 * 
 * This code is licensed under the MIT License
 * 
 * SEE: http://harnessit.codeplex.com/license
 * 
 */
using System;
using System.Collections;

namespace UnitedBinary.Core.Diagnostics
{
	/// <summary>
	/// Summary description for StackTraceParser.
	/// </summary>
	public class StackTraceParser
	{
		private StackTraceEntry[] entries = new StackTraceEntry [0];

		public StackTraceParser(string stackTrace)
		{
			LoadStackTrace(stackTrace);
		}

		public StackTraceEntry[] Entries
		{
			get
			{
				return entries;
			}
		}

		private void LoadStackTrace(string stackTrace)
		{
			if (stackTrace == null)
			{
				throw new Exception("Stack trace cannot be null.");
			}

			if (stackTrace.Length == 0)
			{
				entries = new StackTraceEntry [0];
				return;
			}

			ArrayList entriesList = new ArrayList();

			string[] stackTraceLines = stackTrace.Split(new char[] {'\n'});
			foreach (string s in stackTraceLines)
			{
				//
				// Columns:
				//
				// Method | Class | Namespace | File | Line
				//

				// Take of any left over \n's and whitespace.
				string temp = s.Trim().Trim(new char[] {'\n'});

				// Remove the "at " part of  "at HERE ...".
				int i = temp.IndexOf("at ");
				if (i >= 0)
				{
					temp = temp.Substring(i+3).Trim();
				}

				string namespaceText	= temp;
				string classText		= "";
				string methodText		= "";
				string fileText			= "";
				string fileLineText		= "";
				string tmpName			= "";

				//
				// Determine whether this line in the stack trace has file information.
				//
				i = temp.IndexOf(" in ");
				if (i < 0)	// No file info.
				{
					tmpName = temp;
				}
				else		// Contains file info.
				{
					tmpName = temp.Substring(0, i + 1);
					temp = temp.Substring(i + 4, temp.Length - i - 4);

					i = temp.IndexOf(":", 4);
					fileText = temp.Substring(0, i);
					fileLineText = temp.Substring(i + 1, temp.Length - i - 1);
					fileLineText = fileLineText.Substring(5);
				}

				// Split up the full name: namespace.class.method.
				string[] pieces = tmpName.Split(new char[] {'.'});
				methodText = pieces[pieces.Length - 1];
				classText = pieces[pieces.Length - 2];

				// Rebuild just the class.method, then remove it from the end.
				// what's left is the namespace.
				string ending = "." + classText + "." + methodText;
				i = namespaceText.IndexOf(ending);
				namespaceText = tmpName.Substring(0, i);

				int line = -1;
				try
				{
					line = Convert.ToInt32(fileLineText);
				}
				catch {}

				//
				// Create a new list view item based on this information and add it to the list view.
				//
				StackTraceEntry entry = new StackTraceEntry(methodText, classText, fileText, namespaceText, line);
				entriesList.Add(entry);
			}

			entries = new StackTraceEntry [entriesList.Count];
			entriesList.CopyTo(entries);
		}
	}
}
